






#ifndef _C_TRANSFORM_H_
#define _C_TRANSFORM_H_





//#include"sl_.h"

#include"sl_point.h"
#include"sl_matrix.h"


//变换和坐标系都默认是右手系的。

/// <summary>
/// 四元数结构体。
/// 四元数最重要的特点是可以对旋转进行插值。
/// </summary>
typedef struct _quaternion____
{
	/*
		w = cosf(theta);
		x = sinf(theta) * iv.x; //iv是三维空间的单位旋转矢量，旋转以逆时针为正
		y = sinf(theta) * iv.y;
		z = sinf(theta) * iv.z;
	*/
	real_t w;
	real_t x;
	real_t y;
	real_t z;
}quaternion;

/// <summary>
/// 三维空间旋转平移矩阵结构体。
/// newP = oldP * Matrix.如果有新的变换要加上去，可以直接在矩阵右边乘上新的矩阵。矩阵可以做旋转，平移变换
/// newP，oldP是三维矢量
/// </summary>
typedef struct _translate_and_rotate_matrix____   // 旋转平移矩阵。 
{
	real_t
		m00, m01, m02, m03,
		m10, m11, m12, m13,
		m20, m21, m22, m23,
		m30, m31, m32, m33;
}trmat;

/// <summary>
/// 欧拉角结构体。
/// 欧拉角固定旋转顺序：先旋转x轴，再旋转y轴，最后的z轴。逆时针为正方向。
/// </summary>
typedef struct __EulerAngles__
{
	//x，y，z方向的欧拉角
	//弧度制，角度范围是0 -- 2PI
	real_t angle_x;
	real_t angle_y;
	real_t angle_z;
}eulerAngle;



/// <summary>
/// 使用旋转矢量和旋转角度初始化四元数
/// </summary>
/// <param name="q">四元数</param>
/// <param name="v">旋转矢量</param>
/// <param name="theta">旋转角度，弧度制的（-PI——PI）</param>
void quaternion_init(quaternion* q, vec3 v, real_t theta);

/// <summary>
/// 单位化，不改变旋转方向等信息，只把四元数伸缩成单位长度
/// </summary>
/// <param name="q">单位化的四元数</param>
void quaternion_normalize(quaternion* q);

void quaternion_print(quaternion q);

/// <summary>
/// 计算四元数的叉乘。q * a
/// </summary>
/// <param name="q">四元数</param>
/// <param name="a">四元数</param>
/// <returns> q * a </returns>
quaternion quaternion_mul(quaternion q, quaternion a);

/// <summary>
/// 计算共轭四元数
/// </summary>
/// <param name="a">四元数</param>
/// <returns>共轭四元数</returns>
quaternion quaternion_conj(quaternion a);

/// <summary>
/// 用四元数旋转三维矢量v
/// </summary>
/// <param name="q">四元数</param>
/// <param name="v">三维矢量</param>
/// <returns>旋转后的三维矢量</returns>
vec3 quaternion_rotate_usemul(quaternion q, vec3 v);

/// <summary>
/// 用四元数旋转三维矢量v
/// </summary>
/// <param name="q">四元数</param>
/// <param name="v">三维矢量</param>
/// <returns>旋转后的三维矢量</returns>
vec3 quaternion_rotate(quaternion q, vec3 v);

/// <summary>
/// 在四元数q的表示的旋转基础上，再绕X轴旋转theta角度
/// </summary>
/// <param name="q">原来的四元数</param>
/// <param name="theta">旋转角度</param>
/// <returns>旋转后的四元数</returns>
quaternion quaternion_rotateX(quaternion q, real_t theta);

/// <summary>
/// 在四元数q的表示的旋转基础上，再绕Y轴旋转theta角度
/// </summary>
/// <param name="q">原来的四元数</param>
/// <param name="theta">旋转角度</param>
/// <returns>旋转后的四元数</returns>
quaternion quaternion_rotateY(quaternion q, real_t theta);

/// <summary>
/// 在四元数q的表示的旋转基础上，再绕Z轴旋转theta角度
/// </summary>
/// <param name="q">原来的四元数</param>
/// <param name="theta">旋转角度</param>
/// <returns>旋转后的四元数</returns>
quaternion quaternion_rotateZ(quaternion q, real_t theta);

/// <summary>
/// 给q0,q1两个四元数插值。t是0-1的参数，表示从q0到q1.
/// </summary>
/// <param name="q0">四元数起点</param>
/// <param name="q1">四元数终点</param>
/// <param name="t">差值的参数</param>
/// <returns>两个四元数的差值</returns>
quaternion quaternion_slerp(quaternion q0, quaternion q1, real_t t);





/// <summary>
/// 单位化矩阵
/// </summary>
/// <param name="tm">被单位化的矩阵</param>
void trmat_identity(trmat* tm);

/// <summary>
/// 旋转平移矩阵与4*4矩阵的复制	//如果不是4*4的矩阵，就不复制。
/// tr << tm
/// </summary>
/// <param name="tr">旋转平移矩阵</param>
/// <param name="tm">4*4矩阵</param>
void trmat_copyfrom(trmat* tr, mat tm);

/// <summary>
/// 旋转平移矩阵与4*4矩阵的复制	//如果不是4*4的矩阵，就不复制。
/// this >> tm
/// </summary>
/// <param name="tr">旋转平移矩阵</param>
/// <param name="tm">4*4矩阵</param>
void trmat_copyto(trmat* tr, mat tm);

//用这个矩阵变换向量v0,旋转结果传递给v1。this*v0=v1

/// <summary>
/// 使用矩阵变换向量v0
/// </summary>
/// <param name="tr">旋转平移矩阵</param>
/// <param name="v0">待变换矢量</param>
/// <returns>变换后的矢量</returns>
vec3 trmat_transform(trmat tr, vec3 v0);

/// <summary>
/// 乘法计算 tm0 * tm1
/// </summary>
/// <param name="tm0">旋转平移矩阵</param>
/// <param name="tm1">旋转平移矩阵</param>
/// <returns> tm0 * tm1</returns>
trmat trmat_mul(trmat tm0, trmat tm1);

/// <summary>
/// 坐标系的原点位置，是默认还有一个大的背景坐标系（大地坐标系）。
/// 获得变换矩阵。根据坐标系0的原点位置，xyz方向，坐标系1的原点位置，xyz方向，计算从坐标系0变换到坐标系1的矩阵。
/// 设空间中一点p在坐标系0的坐标的p0，坐标系1的坐标是p1，两个坐标系之间的变换矩阵是this，则 p0 * this = p1.    
/// </summary>
/// <param name="position_0">  坐标系0的原点位置</param>
/// <param name="direction_0x">坐标系0的x轴方向</param>
/// <param name="direction_0y">坐标系0的y轴方向</param>
/// <param name="direction_0z">坐标系0的z轴方向</param>
/// <param name="position_1">  坐标系1的原点位置</param>
/// <param name="direction_1x">坐标系1的x轴方向</param>
/// <param name="direction_1y">坐标系1的y轴方向</param>
/// <param name="direction_1z">坐标系1的z轴方向</param>
/// <returns>从坐标系0变换到坐标系1的变换矩阵</returns>
trmat trmat_get_transformMatrix(
	vec3 position_0, vec3 direction_0x, vec3 direction_0y, vec3 direction_0z,
	vec3 position_1, vec3 direction_1x, vec3 direction_1y, vec3 direction_1z);


/// <summary>
/// 在变换矩阵tm的基础上，增加平移变换
/// </summary>
/// <param name="tm">原矩阵</param>
/// <param name="tx">x方向平移量</param>
/// <param name="ty">y方向平移量</param>
/// <param name="tz">z方向平移量</param>
/// <returns>增加平移变换后的矩阵</returns>
trmat trmat_translate(trmat tm, real_t tx, real_t ty, real_t tz);

/// <summary>
/// 在变换矩阵tm的基础上，增加比例缩放变换
/// </summary>
/// <param name="tm">原矩阵</param>
/// <param name="sx">x方向缩放系数</param>
/// <param name="sy">y方向缩放系数</param>
/// <param name="sz">z方向缩放系数</param>
/// <returns>增加平移变换后的矩阵</returns>
trmat trmat_scale(trmat tm, real_t sx, real_t sy, real_t sz);

/// <summary>
/// 在变换矩阵tm的基础上，再绕X轴旋转theta角度
/// </summary>
/// <param name="tm">原矩阵</param>
/// <param name="theta">旋转角度</param>
/// <returns>旋转后的矩阵</returns>
trmat trmat_rotateX(trmat tm, real_t theta);

/// <summary>
/// 在变换矩阵tm的基础上，再绕Y轴旋转theta角度
/// </summary>
/// <param name="tm">原矩阵</param>
/// <param name="theta">旋转角度</param>
/// <returns>旋转后的矩阵</returns>
trmat trmat_rotateY(trmat tm, real_t theta);

/// <summary>
/// 在变换矩阵tm的基础上，再绕Z轴旋转theta角度
/// </summary>
/// <param name="tm">原矩阵</param>
/// <param name="theta">旋转角度</param>
/// <returns>旋转后的矩阵</returns>
trmat trmat_rotateZ(trmat tm, real_t theta);

void trmat_print(trmat tm);


/// <summary>
/// 使用欧拉角旋转矢量v0，按照xyz的顺序旋转
/// </summary>
/// <param name="e">欧拉角</param>
/// <param name="v0">原三维矢量</param>
/// <returns>旋转后的三维矢量</returns>
vec3 eulerAngle_rotate(eulerAngle e, vec3 v0);

void eulerAngle_print(eulerAngle e);

/// <summary>
/// 从四元数中获取变换矩阵
/// </summary>
/// <param name="q">四元数</param>
/// <returns>变换矩阵</returns>
trmat quaternion_get_trmat(quaternion q);

/// <summary>
/// 从四元数获取欧拉角
/// </summary>
/// <param name="q">四元数</param>
/// <returns>欧拉角</returns>
eulerAngle quaternion_get_eulerAngle(quaternion q);

/// <summary>
/// 从旋转矩阵获取欧拉角 （不考虑平移分量）
/// </summary>
/// <param name="tm">旋转矩阵</param>
/// <returns>欧拉角</returns>
eulerAngle trmat_get_eulerAngle(trmat tm);

/// <summary>
/// 从旋转矩阵获取四元数（不考虑平移分量）
/// </summary>
/// <param name="tm">旋转矩阵</param>
/// <returns>四元数</returns>
quaternion trmat_get_quaternion(trmat tm);

/// <summary>
/// 从欧拉角获取旋转矩阵
/// </summary>
/// <param name="euler">欧拉角</param>
/// <returns>旋转矩阵</returns>
trmat eulerAngle_get_trmat(eulerAngle euler);

/// <summary>
/// 从欧拉角获取四元数
/// </summary>
/// <param name="euler">欧拉角</param>
/// <returns>四元数</returns>
quaternion eulerAngle_get_quaternion(eulerAngle euler);

/// <summary>
/// 从欧拉角获取四元数
/// </summary>
/// <param name="euler">欧拉角</param>
/// <returns>四元数</returns>
quaternion eulerAngle_get_quaternion_by_rotate(eulerAngle euler);

//检查四元数的变换。看用四元数乘法计算的旋转于普通计算之间的关系。
void test_Quaternion(void);

//测试欧拉角的计算
void test_EulerAngles(void);

//检查trmat的乘法运算。
void test_TransformMatrix(void);

//测试三种表达方式的转化。
void test_transform(void);

//测试反向变换
void test_fanxiangbianhuan(void);





#endif


